package com.gitee.wsl.compose.modifier.context

import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.modifier.ModifierLocalReadScope
import androidx.compose.ui.modifier.ProvidableModifierLocal
import androidx.compose.ui.modifier.modifierLocalConsumer
import androidx.compose.ui.modifier.modifierLocalProvider
import com.gitee.wsl.compose.modifier.ModifierContextScope

/**
 *  val sharedKey = modifierLocalOf { "null" }
 * 	Modifier
 * 		.modifierLocalProvider(sharedKey) {
 * 			// 提供一个默认值
 * 			"defaultValue"
 * 		}
 * 		.modifierLocalConsumer {
 * 			// 通过 key.current 获取 value 返回
 * 			println(sharedKey.current)
 * 		}
 */
//LayoutModifier 提供了一个局部变量 widthString，期望能够在下一个 LayoutModifier 能使用这个变量，这种业务场景就可以使用 ModifierLocal
@OptIn(ExperimentalComposeUiApi::class)
fun <T> ModifierContextScope.localProvider(key: ProvidableModifierLocal<T>, value: () -> T){
    modifier = modifier.modifierLocalProvider(key, value)
}

@OptIn(ExperimentalComposeUiApi::class)
fun <T> ModifierContextScope.localConsumer(consumer: ModifierLocalReadScope.() -> Unit){
    modifier = modifier.modifierLocalConsumer(consumer)
}


/**
 * 通过 ModifierLocalProvider 提供要共享的数据，ModifierLocalConsumer 提供要获取的数据。但是上面的写法只能做到变量在这两个函数之间共享
 *
 * 要让其他 Modifier 也能拿到共享的数据，就需要自己去实现 ModifierLocalProvider 和 ModifierLocalConsumer 的接口
 */

/**
 * setContent {
 *     Text(
 *         "text",
 *         Modifier
 *             .then(object : LayoutModifier, ModifierLocalProvider<Array<String>> {
 *                 val widthString = arrayOf("")
 *
 *                 override fun MeasureScope.measure(
 *                     measurable: Measurable,
 *                     constraints: Constraints
 *                 ): MeasureResult {
 *                     val placeable = measurable.measure(constraints)
 *                     widthString[0] = placeable.width.toString()
 *                     return layout(placeable.width, placeable.height) {
 *                         placeable.placeRelative(0, 0)
 *                     }
 *                 }
 *
 *                 override val key: ProvidableModifierLocal<Array<String>>
 *                     get() = sharedWithKey
 *
 *                 // 因为在某些场景我们无法确认 widthString 的赋值比获取提前
 *                 // 如果 widthString 是 String 类型，可能就会出现异常
 *                 // 所以这里通过一个包装确保即使提前获取了，也是有一个默认值存在，这里用的 Array 包装
 *                 override val value: Array<String>
 *                     get() = widthString
 *
 *             })
 *             .then(object : LayoutModifier, ModifierLocalConsumer {
 *                 lateinit var sharedString: String
 *
 *                 override fun MeasureScope.measure(
 *                     measurable: Measurable,
 *                     constraints: Constraints
 *                 ): MeasureResult {
 *                     val placeable = measurable.measure(constraints)
 *                     return layout(placeable.width, placeable.height) {
 *                         placeable.placeRelative(0, 0)
 *                     }
 *                 }
 *
 *                 override fun onModifierLocalsUpdated(scope: ModifierLocalReadScope) =
 *                     with(scope) {
 *                         sharedString = sharedWithKey.current[0]
 *                     }
 *             })
 *     )
 */

/**
 * 更多时候 ModifierLocalProvider 和 ModifierLocalConsumer 会在 Modifier 共同实现，用于承接上游和下游的数据共享，比如 Modifier.windowInsetsPadding()：
 *
 * Modifier.windowInsetsPadding(WindowInsets(4.dp, 4.dp, 4.dp, 4.dp))
 *     .windowInsetsPadding(WindowInsets(4.dp, 6.dp, 4.dp, 6.dp))
 *     .windowInsetsPadding(WindowInsets(4.dp, 2.dp, 4.dp, 2.dp))
 *
 * WindowInsetsPadding.kt
 *
 * // 实现了 ModifierLocalConsumer 和 ModifierLocalProvider
 * internal class InsetsPaddingModifier(
 * 	private val insets: WindowInsets,
 * 	inspectorInfo: InspectorInfo.() -> Unit = debugInspectorInfo {
 * 		name = "InsetsPaddingModifier"
 * 		properties["insets"] = insets
 * 	}
 * ) : InspectorValueInfo(inspectorInfo), LayoutModifier,
 * 	ModifierLocalConsumer, ModifierLocalProvider<WindowInsets> {
 * 	private var unconsumedInsets: WindowInsets by mutableStateOf(insets)
 * 	private var consumedInsets: WindowInsets by mutableStateOf(insets)
 *
 * 	override fun MeasureScope.measure(
 * 		measurable: Measurable,
 * 		constraints: Constraints
 * 	): MeasureResult {
 * 		...
 * 	}
 *
 * 	// 上游提供数据时就在这里处理好先存起来，下游去取时就能拿到处理好的数据
 * 	// Compose 能保证上游提供数据的时候下游是还没取的流程
 * 	override fun onModifierLocalsUpdated(scope: ModifierLocalReadScope) {
 * 		with(scope) {
 * 			val consumed = ModifierLocalConsumedWindowInsets.current
 * 			unconsumedInsets = insets.exclude(consumed)
 * 			consumedInsets = consumed.union(insets)
 * 		}
 * 	}
 *
 * 	override val key: ProvidableModifierLocal<WindowInsets>
 * 		get() = ModifierLocalConsumedWindowInsets
 *
 * 	override val value: WindowInsets
 * 		get() = consumedInsets
 * }
 */